#include <mips/regdef.h>
#include <sys/syscall.h>
#define SSIZE		(80)
#define	O_RA		(76)
#define	O_FP		(72)
#define	O_GP		(68)
#define O_ARG0		0
#define O_ARG1		4
#define O_ARG2		8
#define BUFFER		16
#define octal		20
#define CONTADOR	24
#define LONGITUD_DELIMITADOR	28
#define sl	32
#define bitsSobrantes	36
#define medio 40
#define conv 44
#define mid	48
#define mult	52
#define contDel 56
#define EJECUCION_CORRECTA                              0
#define ERROR_LECTURA                                   1
#define ERROR_ESCRITURA                                 2
#define ERROR_DELIMITADORES                             3
#define ERROR_ARGUMENTOS_INCORRECTOS    				4
#define ERROR_CARACTERES_INCORRECTOS    				5

#define sr 		5

       .data
		lectura:
			.space	1
		escritura:
			.space	1

		##FIN - Vector "const char *odump_errmsg[]" que contiene los mensajes de error


//int odump encode(int infd, int outfd, struct odump opts *opts)


			.text
			.align 	2
			.globl	odump_encode
			.ent	odump_encode

odump_encode:
			.frame 	$fp,SSIZE,ra
   			.set  	noreorder
   			.cpload t9
   			.set  	reorder

   			## creo stack frame
   			subu	sp,sp,SSIZE
			//sw		gp,O_GP(sp)
			.cprestore	O_GP
			sw		$fp,O_FP(sp)
			sw		ra,O_RA(sp)
			move	$fp,sp
			sw		a0,O_ARG0($fp)
			sw		a1,O_ARG1($fp)
			sw		a2,O_ARG2($fp)

			## calculo longitud del delimitador
			lw		t0,O_ARG2($fp)
			lw		a0,4(t0)
			la		t9,mystrlen
			jal		ra,t9
			sw		v0,LONGITUD_DELIMITADOR($fp)

			## inicializo contador para longitud por linea
			sw		zero,CONTADOR($fp)

			//inicializo para moverme en los bits
			sw		zero,sl($fp)

			li		v0,SYS_read
			lw		a0,O_ARG0($fp)		## a0 = infd
			la		a1,BUFFER($fp)		## a1 = direccion de BUFFER
			li		a2,1				## a2 = 1 byte
			syscall

			## verifico EOF y errores
			beq		v0,zero,fin_odump_encode	// si v0=0 es EOF
		 	bne		a3,zero,error_lectura_encode	// si a3!=0 hay un error
		 	bne		v0,1,error_lectura_encode		// si no leyo 1 byte hay un error

primeraLectura:
			## inicializo los bits Sobrantes
			lw		t6,bitsSobrantes($fp)	// t6 = bitsSobrantes
			li		t6,8
			sw		t6,bitsSobrantes($fp)	//bitsSobrantes = t6


			## aumento contador
			lw		t6,CONTADOR($fp)	// t6 = CONTADOR
			addiu	t6,t6,1				// t6 = CONTADOR + 1
			sw		t6,CONTADOR($fp)	//CONTADOR = t6

			li 		t0,48 			// t0 = CERO
			//la 		t1,BUFFER($fp)		// t1 = direccion del BUFFER
			lbu 		t1,BUFFER($fp) 			// t1 = *BUFFER
			li 		t2,0 				// t2 contador
		//	la		t3,octal($fp)		// t3 = direccion del VECTOR
			//addiu	t3,t3,2				// aumento 2 posiciones para grabar de atras para adelante

			srl 	t3,t1,6 				//me quedo con los dos primeros bits
			add 	t3,t3,t0 				//le sumo el ascii del 0
			//sb 		t4,0(t3)
			sw		t3,octal($fp)

			//voy guardando los shifts que realizo
			li		t0,2
			sw		t0,sl($fp)

			## resto los bits procesados
			lw		t6,bitsSobrantes($fp)	// t6 = bitsSobrantes
			add		t6,t6,-2				// t6 = bitsSobrantes - 2
			sw		t6,bitsSobrantes($fp)	//bitsSobrantes = t6

			b		escribirOctal

mientras:
			//la 		t1,BUFFER($fp)		// t1 = direccion del BUFFER
			lbu 		t1,BUFFER($fp)//0(t1) 			// t1 = *BUFFER
			lw		t5,sl($fp)

			li 		t3,0

			## resto los bits procesados
			lw		t6,bitsSobrantes($fp)	// t6 = bitsSobrantes
			add		t6,t6,-3				// t6 = bitsSobrantes - 3
			sw		t6,bitsSobrantes($fp)	//bitsSobrantes = t6

			//me quedo con los 3 bits del medio o los ultimos 3, dependiendo del valor de t5
			sll 	t3,t1,t5
			sb 		t3,medio($fp)
			lbu		t3,medio($fp)
			srl		t3,t3,sr
			//mul		t3,t1,t5
			//div		t3,t3,sr

			add 	t3,t3,48 			//le sumo el ascii del 0
			sw		t3,octal($fp)
			//sb 		t4,0(t3)
			addiu	t5,t5,3
			sw		t5,sl($fp)
			b		escribirOctal		//lo escribo en el archivo

escribirOctal:
			## escribe el octal
			li		v0,SYS_write
			lw		a0,O_ARG1($fp)		// a0 = outfd
			la		a1,octal($fp)		// a1 = direccion del octal
			li		a2,1				// a2 = 1 byte
			syscall

			## verifico de errores de escritura
			bne		v0,1,error_escritura_encode		// si no escribio 1 byte hay un error

			//mientras bitsSobrantes <> 0 -> proceso el resto de los bits
			lw		t6,bitsSobrantes($fp)	// t6 = bitsSobrantes
			bne		t6,zero, mientras

leer1byte:
			li		v0,SYS_read
			lw		a0,O_ARG0($fp)		## a0 = infd
			la		a1,BUFFER($fp)		## a1 = direccion de BUFFER
			li		a2,1				## a2 = 1 byte
			syscall

			## verifico EOF y errores
			beq		v0,zero,fin_odump_encode	// si v0=0 es EOF
		 	bne		a3,zero,error_lectura_encode	// si a3!=0 hay un error
		 	bne		v0,1,error_lectura_encode		// si no leyo 1 byte hay un error
proximoByte:

			## si es stdin y se leyo ya el salto de linea es fin
			beq  s2,1,fin_odump_encode

			//## vuelvo a leer el siguiente byte
			//b primeraLectura
			## pongo delimitador o /n
BarraEneoDelim:
			## calculo si hay que hacer salto de linea o escribir el delimitador
			lw		t0,O_ARG2($fp)		// t0 = odump_pts
			lw		t0,0(t0)			//## t0 = length
			lw		t1,CONTADOR($fp)	//## t1 = CONTADOR
			beq		t0,t1,saltoDeLinea	//## lenght=CONTADOR -> salto de linea
			beq		t0,zero,escribirDelimitador	//## length=0 -> primeraLectura

escribirDelimitador:
			## escribe el delimitador
			li		v0,SYS_write
			lw		a0,O_ARG1($fp)		// a0 = outfd
			lw		t0,O_ARG2($fp)		// t0 = odump_pts
			lw		a1,4(t0)			// a1 = direccion de delimitador
			lw		a2,LONGITUD_DELIMITADOR($fp)	// a2 = longitud delimitador
			syscall

			## verifico de errores de escritura
			lw		t0,LONGITUD_DELIMITADOR($fp)	// t0 = longitud delimitador
		 	bne		v0,t0,error_escritura_encode	// si no escribio la cantidad de bytes del delimitador hay error
		 	b		primeraLectura	//## lenght!=CONTADOR -> proximoByte

saltoDeLinea:
			li		v0,SYS_write
			lw		a0,O_ARG1($fp)		## a0 = outfd
			la		a1,newLine			## a1 = direccion de newLine
			li		a2,1				## a2 = 1 byte
			syscall

			## verifico de errores de escritura
			bne		v0,1,error_escritura_encode		## si no escribio 1 byte hay un error

			## vuelvo a inicializar CONTADOR

			sw		zero,CONTADOR($fp)

			b primeraLectura



error_lectura_encode:
			li		v0,ERROR_LECTURA
			b		fin_odump_encode

error_escritura_encode:
			li		v0,ERROR_ESCRITURA
			b		fin_odump_encode

ejecucion_correcta_encode:
			## si llego aca es porque hay que escribir el salto de linea
			li		v0,SYS_write
			lw		a0,O_ARG1($fp)		## a0 = outfd
			la		a1,newLine			## a1 = direccion de newLine
			li		a2,1				## a2 = 1 byte
			syscall
			## verifico de errores de escritura
			bne		v0,1,error_escritura_encode		// si no escribio 1 byte hay un error

			li		v0,EJECUCION_CORRECTA

fin_odump_encode:

			## destruyo stack frame
			move	sp,$fp
			lw		gp,O_GP(sp)
			lw		$fp,O_FP(sp)
			lw		ra,O_RA(sp)
			addiu	sp,sp,SSIZE
			jr		ra
			.end	odump_encode

			.data
newLine:
			.ascii 	"\n"
error_encode:
			.ascii	"Se ha producido un error\n"

########################################################################################################################################################

		####		STACK FRAME DECODE
		####	tengo 3 parametros punteros,
		####	6 variables locales y
		####	es no leaf con 2 parametros (llama a convertir)
		####
		####	  68|--------------|
		####		|     opt	   |
		####	  64|--------------|
		####		|	   fout    |
		####	  60|--------------|
		####		|      f       |
		####	  56|--------------|
		####		|\\\\\\\\\\\\\\|
		####	  52|--------------|
		####		|      ra      |
		####	  48|--------------|	R
		####		|	   fp      |	A
		####	  44|--------------|
		####		|      gp      |
		####	  40|--------------|##---
		####	  	|    int k     |
		####	  36|--------------|
		####	  	|     int j    |	L
		####	  32|--------------|	T
		####	  	|     int mid  |	A
		####	  28|--------------|
		####	  	|     int conv |
		####	  24|--------------|
		####	  	| 	  int i    |
		####	  20|--------------|
		####	  	|     int bin  |
		####	  16|--------------|##---
		####		|\\\\\\\\\\\\\\|
		####	  12|--------------|	A
		####		| int delim	   |    B
		####	   8|--------------|	A
		####		|    int i     |
		####	   4|--------------|
		####		||char bin|\\\\|
		####	   0|--------------|##--

	.text                   	## codigo en sector del texto
	.align 2
	.ent 	odump_decode        ## declaro el nombre de la funcion
	.globl 	odump_decode       	## declaro que sera global

odump_decode:
			.frame 	$fp,SSIZE,ra
   			.set  	noreorder
   			.cpload t9
   			.set  	reorder

   			## creo stack frame
   			subu	sp,sp,SSIZE
			//sw		gp,O_GP(sp)	310				sw		gp,O_GP(sp)
			.cprestore	O_GP
			sw		$fp,O_FP(sp)
			sw		ra,O_RA(sp)
			move	$fp,sp
			sw		a0,O_ARG0($fp)
			sw		a1,O_ARG1($fp)
			sw		a2,O_ARG2($fp)

			## calculo longitud del delimitador
			lw		t0,O_ARG2($fp)
			lw		a0,4(t0)
			la		t9,mystrlen
			jal		ra,t9
			sw		v0,LONGITUD_DELIMITADOR($fp)

			## defino e inicializo variables locales
			sw 		zero,conv($fp)		## conv=0
			sw 		zero,mid($fp)		## mid=0
			sw		zero,contDel($fp)
			li		t1,3
			sw		t1,CONTADOR($fp)
			li		t2,64
			sw		t2,mult($fp)


leerbyte:
			li		v0,SYS_read
			lw		a0,O_ARG0($fp)		## a0 = infd
			la		a1,BUFFER($fp)		## a1 = direccion de BUFFER
			li		a2,1				## a2 = 1 byte
			syscall


			## verifico EOF y errores
			beq		v0,zero,ejecucion_correcta_decode	// si v0=0 es EOF
		 	bne		a3,zero,error_lectura_decode	// si a3!=0 hay un error
		 	bne		v0,1,error_lectura_decode		// si no leyo 1 byte hay un error

		 	//si el contador = -1 -> resetVar y luego siguienteByte
		 	//lw		t0,CONTADOR($fp)
		 	//beq		t0,-1,resetVar

for:
			//si el contador vale 0, escribo en el archivo
		 	lw		t0,CONTADOR($fp)
		 	beq		t0,zero,escribirBinario

			lb 		t1,BUFFER($fp)

			bge		t1,56, error_caracteres_incorrectos_decode
			blt		t1,48, error_caracteres_incorrectos_decode

			lw			t5,mult($fp)
			//le resto el ascii del 0
			sub			t3,t1,48
			//multiplico por la potencia
			mul			t3,t3,t5
			//resto 1 a contador y lo guardo
			sub			t0,t0,1
			sw			t0,CONTADOR($fp)
			//guardo lo que va a imprimir en mid
			lw			t4,mid($fp)
			add			t4,t4,t3
			sw			t4,mid($fp)
			//voy dividiendo por 8 para obtener el multiplo correcto por el que tengo que multiplicar
			//cada digito del octal.
			div			t5,t5,8
			sw			t5,mult($fp)
			b			leerbyte

escribirBinario:

			## escribe el binario
			li		v0,SYS_write
			lw		a0,O_ARG1($fp)		// a0 = outfd
			la		a1,mid($fp)			// a1 = direccion del binario
			li		a2,1				// a2 = 1 byte
			syscall
			## verifico de errores de escritura
			bne		v0,1,error_escritura_decode		// si no escribio 1 byte hay un error

resetVar:
			//Vuelvo el multiplicador a 64
			li		t2,64
			sw		t2,mult($fp)
			//Vuelvo el mid a 0
			sw 		zero,mid($fp)		## mid=0
			//vuelvo el contador a 3
			li		t3,3
			sw		t3,CONTADOR($fp)
			sw		zero,contDel($fp)

siguienteByte:
			lb 	    t1,BUFFER($fp)
		 	//la		t2,nl					##Cargo ASCII '\n'
		 	beq		t1,10,leerbyte

		 	lw		t3,LONGITUD_DELIMITADOR($fp)
		 	li		t4,0
		 	beq		t4,t3,for

saltearDelimitador:
			lw		t1,LONGITUD_DELIMITADOR($fp)
			lw		t2,contDel($fp)
			add		t2,t2,1
			sw		t2,contDel($fp)
			//comparo antes de lrer porque ya lei el byte siguiente al octal, ergo tengo que leer
			//LONGITUD_DELIMITADOR - 1
			beq		t2,t1,leerbyte
			li		v0,SYS_read
			lw		a0,O_ARG0($fp)		## a0 = infd
			la		a1,BUFFER($fp)		## a1 = direccion de BUFFER
			li		a2,1		## a2 = 1
			syscall
			bne		t2,t1,saltearDelimitador
			b		leerbyte
ejecucion_correcta_decode:
			li		v0,EJECUCION_CORRECTA
			b		fin_odump_decode
error_caracteres_incorrectos_decode:
			li		v0,ERROR_CARACTERES_INCORRECTOS
			b		fin_odump_decode

error_lectura_decode:
			li		v0,ERROR_LECTURA
			b		fin_odump_decode

error_escritura_decode:
			li		v0,ERROR_ESCRITURA
			b		fin_odump_decode
fin_odump_decode:
			## destruyo stack frame
			move	sp,$fp
			lw		gp,O_GP(sp)
			lw		$fp,O_FP(sp)
			lw		ra,O_RA(sp)
			addiu	sp,sp,SSIZE
			jr		ra

   		.end odump_decode         	## fin odump_decode

	.ent	mystrlen
mystrlen:
		.frame	$fp, 16, ra
		subu	sp, sp, 16
		.cprestore 0
		sw		$fp, 4(sp)
		move	$fp, sp

		li		v0, 0 				## Use v0 for the result.
		beqz 	a0, mystrlen_return
mystrlen_loop:
		lb		t0, 0(a0)
		beqz	t0, mystrlen_return
		addiu	a0, a0, 1
		addiu	v0, v0, 1
		j		mystrlen_loop

mystrlen_return:

		lw		$fp, 4(sp) 			## Destruimos el frame.
		addu	sp, sp, 16


		j		ra					## Retorno.
		.end	mystrlen


		.rdata
			.extern ejecucion_correcta
ejecucion_correcta:
			.asciiz	"Ejecución correcta"
			.extern	error_lectura
error_lectura:
			.asciiz	"ERROR en lectura"
			.extern	error_escritura
error_escritura:
			.asciiz	"ERROR en escritura"
			.extern	error_delimitador
error_delimitador:
			.asciiz	"ERROR delimitador incorrecto"
			.extern error_argumentos_incorrectos
error_argumentos_incorrectos:
			.asciiz	"ERROR argumentos incorrectos"
			.extern	odump_errmsg
error_caracteres_incorrectos:
			.asciiz	"ERROR caracteres incorrectos"
			.extern	odump_errmsg
			.align 2
odump_errmsg:
	.word	ejecucion_correcta, error_lectura, error_delimitador, error_argumentos_incorrectos, error_caracteres_incorrectos

	nl:
			.ascii 	"\n"
